﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using HCM_maps_website.Models;
using HCM_maps_website.Process.DAL;

namespace HCM_maps_website.Process.BLL
{
    public struct SearchResult
    {
        public List<ServiceModel> Service;
        public List<PlaceModels> Place;
    };

    public class SearchBLL
    {
        private static List<string> NormalizeKeyword(string keyWord)
        {
            if (keyWord.Length == 0) return null;
            //Remove muti space
            string result = StringHelper.StandardizeString(keyWord);
            string path = HttpContext.Current.Server.MapPath("../abbreviation.xml");

            //Not split
            string orignal = result;
            orignal = StringHelper.GetSearchString(orignal, path);


            //Split number and street (if need)
            List<string> addr = StringHelper.GetNumberAndStreet(result);

            addr[addr.Count - 1] = StringHelper.GetSearchString(addr[addr.Count - 1], path);

            if (addr.Count == 1)
                addr.Insert(0, "");

            addr.Add(orignal);
            
            return addr;
        }

        public static SearchResult Search(string keyword)
        {
            /*keyword = keyword.Trim();
            ServiceBLL s = new ServiceBLL();
            PlaceBLL p = new PlaceBLL();
            List<ServiceModel> service = new List<ServiceModel>();
            List<PlaceModels> place = new List<PlaceModels>();

            List<string> addr = NormalizeKeyword(keyword);

            if (addr[0] == "")
                place = p.FindWithoutNumber(addr[1]);
            else
            {
                place = (List<PlaceModels>)p.FindExactAddress(addr[0], addr[1]);
                if (place.Count == 0)
                {
                    place = (List<PlaceModels>)p.FindNearAddress(addr[0], addr[1]);
                }
            }

            service = (List<ServiceModel>)s.FindServiceByKeyword(addr[2]);
            if (service.Count == 0)
                service = AdvanceSearch(keyword);

            List<ServiceModel> rest = FindTotal(keyword);
            service.AddRange(rest);

            SearchResult result = new SearchResult();
            result.Place = place;
            result.Service = service;
            return result;*/

            ServiceBLL s = new ServiceBLL();
            PlaceBLL p = new PlaceBLL();
            List<ServiceModel> service = new List<ServiceModel>();
            List<PlaceModels> place = new List<PlaceModels>();

            List<string> addr = NormalizeKeyword(keyword);

            if (addr[0] == "")
                place = p.FindWithoutNumber(addr[1]);
            else
            {
                place = (List<PlaceModels>)p.FindExactAddress(addr[0], addr[1]);
                if (place.Count == 0)
                {
                    place = (List<PlaceModels>)p.FindNearAddress(addr[0], addr[1]);
                }
            }

            service = SearchServiceAndPlace(keyword);
            if (service.Count == 0)
                service = (List<ServiceModel>)s.FindServiceByKeyword(addr[2]);

            SearchResult result = new SearchResult();
            result.Place = place;
            result.Service = service;
            return result;

        }

        public List<ServiceModel> GetServiceByDistance(int typeID,Coordinate c, int limit)
        {
            ServiceDAO s = new ServiceDAO();
            return (List<ServiceModel>)s.GetServiceByPlaceTypeAndDistance(typeID, c, limit);
        }

        public static ServiceModel GetNearPlaceCoordinate(Coordinate c)
        {
            ServiceModel result = new ServiceModel();
            PlaceDAO p = new PlaceDAO();
            PlaceModels place =  p.GetNearCoordinate(c);
            ServiceDAO s = new ServiceDAO();
            List<ServiceModel> service = (List<ServiceModel>)s.GetServiceAround(c, 100);

            if (service.Count > 0)
            {
                if (Coordinate.Distance(c, place.Coordinate) < Coordinate.Distance(c, service[0].Coordinate))
                {
                    result.Coordinate = place.Coordinate;
                    result.Address = place.HomeNumber + " " + place.Area;
                }
                else
                {
                    /*foreach (ServiceModel s in service)
                    {
                    }*/
                    result = service[0];
                }
            }
            else
            {
                result.Coordinate = place.Coordinate;
                result.Address = place.HomeNumber + " " + place.Area;
            }
            return result;
        }
        
        private static List<ServiceModel> AdvanceSearch(string keyword)
        {
            ServiceDAO s = new ServiceDAO();
            ServiceType t = null;
            List<ServiceModel> result = new List<ServiceModel>();

            string[] key;
            int index = -1;

            key = keyword.Split(',');
            for(int i = 0 ; i < key.Length; i++)
            {
                t = s.GetPlaceTypeInfo("\"" + key.ElementAt(i) + "*\"");
                if (t != null)
                {
                    index = i;
                    break;
                }
            }

            if (t != null)
            {
                for (int i = 0; i < key.Count(); i++)
                {
                    if (i != index)
                    {
                        List<string> addr = NormalizeKeyword(key.ElementAt(i));
                        result = s.GetServiceByTypeAndAddress(t.ID, addr[2]);
                        if (result.Count != 0)
                            break;
                    }
                }
                return result;
            }
            return result;
        }

        public static List<ServiceModel> FindTotal(string keyword)
        {
            List<ServiceModel> result = new List<ServiceModel>();
            ServiceDAO s = new ServiceDAO();
            string[] split = keyword.Split(' ');

            string path = HttpContext.Current.Server.MapPath("../abbreviation.xml");
            string des = StringHelper.GetSearchString(split[0], path);

            des = des.Insert(des.LastIndexOf("\""), "*");
            ServiceType type = s.GetPlaceTypeInfo(des);
            if (type != null)
            {
                if (keyword.Length > split[0].Length + 1)
                {
                    string key = keyword.Remove(0, split[0].Length + 1);
                    List<string> addr = NormalizeKeyword(key);
                    result = s.GetServiceByTypeAndAddress(type.ID, addr[2]);
                }
            }
            return result;
        }

        public static List<ServiceModel> SearchServiceAndPlace(string keyword)
        {
            ServiceDAO s = new ServiceDAO();
            List<ServiceModel> result = new List<ServiceModel>();
            List<int> serviceTypeID = new List<int>();
            List<string> Address = new List<string>();

            string path = HttpContext.Current.Server.MapPath("../abbreviation.xml");
            keyword = keyword.Trim();
            string[] finding = keyword.Split(' ');

            string des = "";
            bool flag = false; //Add
            for (int i = 0; ; i++)
            {
                if (!flag)
                {
                    if (des.Length >= keyword.Length)
                    {
                        flag = true;
                        i = -1;
                        des = des.Trim();
                    }
                    else
                    {
                        des += finding.ElementAt(i);
                    }
                }
                else
                {
                    des = des.Remove(0, finding.ElementAt(i).Length);
                    if (des.Length == 0)
                    {
                        break;
                    }
                    else
                    {
                        des = des.TrimStart();
                    }
                }
                string description = StringHelper.GetSearchString(des, path);

                description = description.Insert(description.LastIndexOf("\""), "*");

                description = description.Replace("\"", "*");
                description = description.Replace("(08)", "08 AND ");

                ServiceType type = s.GetPlaceTypeInfo(description);
                if (type != null)
                {
                    serviceTypeID.Add(type.ID);

                    Address.Add(keyword.Remove(flag == false ? keyword.IndexOf(des) : keyword.LastIndexOf(des), des.Length));
                }
                if (!flag)
                    des += " ";

            }

            for (int i = 0; i < serviceTypeID.Count; i++)
            {
                List<string> addr = NormalizeKeyword(Address[i]);
                List<ServiceModel> query = null;
                if (addr != null)
                {
                    query = s.GetServiceByTypeAndAddress(serviceTypeID[i], addr[2]); result.AddRange(query);
                }
            }

            return result;
        }
    }
}